/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = sqlserver_core.c                                              */
/*  NOTE      = TDS协议解析                                                   */
/*  DATE      = 2014/09/28 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#include "frservice_comm.h"
#include "sqlserver_core.h"
#include "sqlserver_common.h"
#include "sqlserver_request.h"
#include "sqlserver_response.h"
#include "config.h"

#define MSSQL_PACKET_HEAD_LEN     8      /* PACKET header的长度 */
#define MSSQL_HASH_COUNT          100    /* 最大hash个数 */
#define MSSQL_MAX_PACKETS         200

extern void *g_p_apm_context;

/*******************************************************************************
*  FUNC     :  初始化私有SQL Server session
*  ARGS     :  p_st_session(SQL Server私有session)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __sqlserver_init_private(L7_session *p_st_session)
{
    Frhash_header *p_st_prepare_hash = NULL;                   /* prepare hash */
    L7_fragment_sqlserver *p_st_fragment = NULL;               /* 分片包相关数据 */
    L7session_sqlserver  *p_st_sqlserver_conn = NULL;          /* 链接信息 */
    L7session_sqlserver_private *p_st_private_session = NULL;  /* SQL Server私有session */

    /* 申请整个私有session结构的内存 */
    p_st_private_session = (L7session_sqlserver_private *)frmalloc(sizeof(L7session_sqlserver_private));
    if (p_st_private_session == NULL)
    {
        goto error;
    }
    memset(p_st_private_session, 0x00, sizeof(L7session_sqlserver_private));

    /* 申请链路信息结构内存 */
    p_st_sqlserver_conn = (L7session_sqlserver *)frmalloc(sizeof(L7session_sqlserver));
    if (p_st_sqlserver_conn == NULL)
    {
        goto error;
    }
    memset(p_st_sqlserver_conn, 0x00, sizeof(L7session_sqlserver));

    /* 申请分片包信息结构内存 */
    p_st_fragment = (L7_fragment_sqlserver *)frmalloc(sizeof(L7_fragment_sqlserver));
    if (p_st_fragment == NULL)
    {
        goto error;
    }
    memset(p_st_fragment, 0x00, sizeof(L7_fragment_sqlserver));

    /* 创建prepare hash */
    p_st_prepare_hash = frhash2_create2(MSSQL_HASH_COUNT);
    if (p_st_prepare_hash == NULL)
    {
        goto error;
    }

    /* 初始化TDS版本信息，客户端和服务端的版本号是独立的 */
    p_st_sqlserver_conn->i_cli_tds_ver = MSSQL_TDS_VER_NULL;
    p_st_sqlserver_conn->i_cli_tds_min_ver = MSSQL_TDS_VER_70;
    p_st_sqlserver_conn->i_cli_tds_max_ver = MSSQL_TDS_VER_74;
    p_st_sqlserver_conn->i_ser_tds_ver = MSSQL_TDS_VER_NULL;
    p_st_sqlserver_conn->i_ser_tds_min_ver = MSSQL_TDS_VER_70;
    p_st_sqlserver_conn->i_ser_tds_max_ver = MSSQL_TDS_VER_74;
    /* 设置初始化结构 */
    p_st_private_session->p_st_sess = p_st_sqlserver_conn;
    p_st_private_session->p_st_fragment = p_st_fragment;
    p_st_private_session->p_hash_prepare = p_st_prepare_hash;
    /* 设置当前链路处于session中 */
    p_st_private_session->i_in_session = FR_NO;
    p_st_session->p_session_private = p_st_private_session;
    return FR_SUCC;

error:
    sqlserver_free((void **)(&p_st_private_session));
    sqlserver_free((void **)(&p_st_sqlserver_conn));
    sqlserver_free((void **)(&p_st_fragment));
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  初始化私有SQL Server session
*  ARGS     :  p_st_private(私有session数据)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :  p_st_private必须不是NULL
*******************************************************************************/
FR_STATIC void __sqlserver_destroy_curr_info(L7session_sqlserver_private *p_st_private)
{
    if (p_st_private->p_st_req)
    {
        sqlserver_destroy_request(&p_st_private->p_st_req);
    }
    if (p_st_private->p_st_resp)
    {
        sqlserver_destroy_response(&p_st_private->p_st_resp);
    }
    sqlserver_init_fragment(p_st_private->p_st_fragment);

    return;
}

/*******************************************************************************
*  FUNC     :  取得完整的packet包
*  ARGS     :  p_st_private(私有session数据)
*           :  p_data(当前数据包数据)
*           :  ui_len(当前数据包数据长度)
*           :  p_st_timestamp(当前数据包发生的时间点)
*           :  p_u8_data_type(当前packet的TDS类型)
*           :  p_i_cancel_flg(当前packet的取消flag)
*  RTN      :  FR_FAIL (true)
*              FR_SUCC (false)
*  NOTE     :  解析失败后需要释放p_st_private里的request/response/fragment信息
*******************************************************************************/
FR_STATIC int __sqlserver_set_analysis_data(L7session_sqlserver_private *p_st_private
                                         , char *p_data
                                         , unsigned int ui_len
                                         , struct timeval *p_st_timestamp
                                         , uint8_t *p_u8_data_type
                                         , int *p_i_cancel_flg
                                         , int *p_i_whole_flg)
{
    int i_ret = FR_SUCC;
    int i_residual_len = 0;
    unsigned short u_size = 0;
    unsigned int ui_add_len = 0;
    unsigned int ui_remain_len = 0;
    unsigned short *p_u_size = NULL;
    char *p_packet_head = NULL;
    char arr_packet_head[MSSQL_PACKET_HEAD_LEN] = {0};
    L7_fragment_sqlserver *p_st_fragment = p_st_private->p_st_fragment;

    *p_i_whole_flg = FR_NO;
    /* 上次packet还遗留的数据长度 */
    ui_remain_len = p_st_fragment->ui_remain_len;
    /* 上次packet还遗留的packet长度 */
    i_residual_len = p_st_fragment->i_residual_packet_head_len;

    /* 创建bytebuffer */
    if (p_st_fragment->p_st_data == NULL)
    {
        /* 做成bytebuffer */
        p_st_fragment->p_st_data = bytebuff_creat();
        if (p_st_fragment->p_st_data == NULL || ui_len <= 8 || p_data[6] != 1)
        {
            return FR_FAIL;
        }
        /* 设置第一个分片包时间 */
        p_st_fragment->st_first_timestamp.tv_sec = p_st_timestamp->tv_sec;
        p_st_fragment->st_first_timestamp.tv_usec = p_st_timestamp->tv_usec;
    }

    //if (frlist_size(p_st_fragment->p_st_data->p_lst_bytebuffer) >= MSSQL_MAX_PACKETS)
    //{
        //frdbg("too many packets[%d]!\n", p_st_private->p_st_fragment->ui_total_len);
        //return FR_FAIL;
    //}

    /* 是一个单独packet的开头 */
    if (ui_remain_len == 0)
    {
        /* request或者response的packet header还没收完,先将部分head保存起来 */
        if ((i_residual_len + ui_len) < MSSQL_PACKET_HEAD_LEN)
        {
            p_packet_head = p_st_fragment->arr_residual_packet_head;
            memcpy(p_packet_head + i_residual_len, p_data, ui_len);
            p_st_fragment->i_residual_packet_head_len += ui_len;
            return FR_SUCC;
        }

        /* request或者response的packet header接收完了 */
        p_packet_head = arr_packet_head;
        memcpy(p_packet_head, p_st_fragment->arr_residual_packet_head, i_residual_len);
        memcpy(p_packet_head + i_residual_len, p_data
               , MSSQL_PACKET_HEAD_LEN - i_residual_len);
        p_st_fragment->i_residual_packet_head_len = 0;
        /* packet头不加入到bytebuffer */
        p_data += MSSQL_PACKET_HEAD_LEN - i_residual_len;
        ui_len -= MSSQL_PACKET_HEAD_LEN - i_residual_len;

        /* 解析packet header */
        /* 1.取得packet的类型 */
        if (*p_u8_data_type == MSSQL_TDS_NUL)/* 一个request或者response的头包 */
        {
            *p_u8_data_type = (uint8_t)*p_packet_head;
        }
        /* 前后packet的类型不一致 */
        else if (*p_u8_data_type != *p_packet_head)
        {
            /* 清除之前的request和response,当做是全新一个packet的开始 */
            __sqlserver_destroy_curr_info(p_st_private);
            /* 做成新的bytebuffer */
            p_st_fragment->p_st_data = bytebuff_creat();
            if (p_st_fragment->p_st_data == NULL)
            {
                return FR_FAIL;
            }
            /* 设置第一个分片包时间 */
            p_st_fragment->st_first_timestamp.tv_sec = p_st_timestamp->tv_sec;
            p_st_fragment->st_first_timestamp.tv_usec = p_st_timestamp->tv_usec;
            *p_u8_data_type = *p_packet_head;
        }

        /* 2.取得packet的结束flag */
        if (*(p_packet_head + 1) & 0x01)
        {
            p_st_fragment->i_end_packet_flg = FR_YES;
            /* 3.取得packet的取消flag */
            if (*(p_packet_head + 1) & 0x02)
            {
                *p_i_cancel_flg = FR_YES;
            }
        }

        /* 4.取得packet的长度 */
        p_u_size = (unsigned short *)(p_packet_head + 2);
        u_size = ntohs(*p_u_size);
        /* packet长度小于8，说明不是完整结构的TDS包 */
        if (u_size < MSSQL_PACKET_HEAD_LEN)
        {
            return FR_FAIL;
        }
        /* total长度将packet header计算在内 */
        p_st_fragment->ui_total_len += u_size;
        /* 实际解药解析数据长度不将packet header计算在内 */
        u_size -= MSSQL_PACKET_HEAD_LEN;
        /* 取得需要追加数据长度 */
        ui_add_len = u_size < ui_len ? u_size : ui_len;
        if (ui_add_len)
        {
            /* 追加buffer */
            i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_add_len);
            if (i_ret != FR_SUCC)
            {
                return FR_FAIL;
            }
        }
        /* 一个数据包中有两个packet header(正常情况下不会发生) */
        if (u_size < ui_len)
        {
            /*
            * 表明一次完整的request或者response已经完成,
            * 如果后续还有数据当做出错, 实际情况不会发生
            */
            if (p_st_fragment->i_end_packet_flg == FR_YES)
            {
                return FR_FAIL;
            }
            else /* 一次完整的request或者response还没完成 */
            {
                p_st_fragment->ui_remain_len = 0;
                i_ret = __sqlserver_set_analysis_data(p_st_private
                                                      , p_data + u_size
                                                      , ui_len - u_size
                                                      , p_st_timestamp
                                                      , p_u8_data_type
                                                      , p_i_cancel_flg
                                                      , p_i_whole_flg);
                if (i_ret != FR_SUCC)
                {
                    return FR_FAIL;
                }
            }
        }
        else
        {
            p_st_fragment->ui_remain_len = u_size - ui_len;
        }
    }
    else
    {
        ui_add_len = ui_remain_len < ui_len ? ui_remain_len : ui_len;
        if (ui_add_len)
        {
            /* 追加buffer */
            i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_add_len);
            if (i_ret != FR_SUCC)
            {
                return FR_FAIL;
            }
        }
        /* 还有剩余的packet head */
        if (ui_remain_len < ui_len)
        {
            p_st_fragment->ui_remain_len = 0;
            i_ret = __sqlserver_set_analysis_data(p_st_private
                                                  , p_data + ui_remain_len
                                                  , ui_len - ui_remain_len
                                                  , p_st_timestamp
                                                  , p_u8_data_type
                                                  , p_i_cancel_flg
                                                  , p_i_whole_flg);
            if (i_ret != FR_SUCC)
            {
                return FR_FAIL;
            }
        }
        else
        {
            p_st_fragment->ui_remain_len -= ui_len;
        }
    }

    /* 判断整个request或者response是否已经结束 */
    if (p_st_fragment->i_end_packet_flg == FR_YES
        && p_st_fragment->ui_remain_len == 0)
    {
        /* 设置最后一个分片包时间 */
        p_st_fragment->st_end_timestamp.tv_sec = p_st_timestamp->tv_sec;
        p_st_fragment->st_end_timestamp.tv_usec = p_st_timestamp->tv_usec;
        *p_i_whole_flg = FR_YES;
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断当前数据链路是否是TDS协议
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_packet(入力数据包)
*  RTN      :  APM_L7_IS_NO   (NO)
*              APM_L7_IS_YES  (YES)
*  NOTE     :
*******************************************************************************/
int sqlserver_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = FR_SUCC;
    int i_sybase = FRTDS_SYBASE_UNKNOW;
    int i_req_resp = FRTDS_DIRECT_UNKNOWN;
    int i_whole_flg = FR_NO;
    uint8_t u8_type = 0;                                 /* packet类型 */
    uint8_t u8_status = 0;                               /* packet状态 */
    uint8_t u8_window = 0;                               /* window按照协议为0 */
    uint16_t u16_len = 0;                                /* packet length */
    unsigned int ui_len = 0;
    char *p_data = NULL;
    Frbyte_Packet *p_st_data = NULL;

    if(p_st_packet == NULL || p_st_packet->p_payload == NULL || p_st_packet->ui_payload_len == 0 || p_st_conn==NULL)
    {
        return APM_L7_IS_NO;
    }

    ui_len = p_st_packet->ui_payload_len;           /* packet数据长度 */
    p_data = p_st_packet->p_payload;                /* packet数据内容 */

    /*
    * 因为TDS的packet必须有8位的packet header,且表示长度的占据两个字节,
    * 所以TDS的packet的长度范围必须是大于等于8且小于等于65535
    */
    if (ui_len < FRTDS_PACKET_HEAD_LEN || ui_len > 65535)
    {
        goto unknown;
    }
    /* 创建bytebuff */
    p_st_data = bytebuff_creat();
    if (p_st_data == NULL)
    {
        goto unknown;
    }
    i_ret = bytebuff_add(p_st_data, p_data, ui_len);
    if (i_ret != FR_SUCC)
    {
        goto unknown;
    }
    /* type位不在协议定义范围之内 */
    i_ret = bytebuff_get_char(p_st_data, &u8_type);
    if (i_ret != FR_SUCC || u8_type == 0x00 || u8_type == 0x05
        || u8_type == 0x0F || u8_type > 0x12
        || (u8_type >= 0x08 && u8_type <= 0x0D))
    {
        goto unknown;
    }
    /*
    * status为0x00,0x01,0x02,0x08或0x00,0x01,0x02,0x10其中一个或多个相与的结果
    * 0xEC为：(0x00 & 0x01 & 0x02 & 0x08)
    * 0xF4为：(0x00 & 0x01 & 0x02 & 0x10)
    * 具体参照协议：2.2.3.1.2 Status
    */
    i_ret = bytebuff_get_char(p_st_data, &u8_status);
    if (i_ret != FR_SUCC || ((u8_status & 0xEC) && (u8_status & 0xF4)))
    {
        goto unknown;
    }

    /* 取得packet的长度(网络字节序) */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (ui_len < u16_len)
    {
        goto unknown;
    }
    /* 确认是否是完整的packet */
    if (u8_status & 0x01)
    {
        i_whole_flg = FR_YES;
    }
    /* 跳过channel和packet number */
    i_ret = bytebuff_skip(p_st_data, 2 + 1);
    if (i_ret != FR_SUCC)
    {
        goto unknown;
    }

    /* 取得window的值 */
    i_ret = bytebuff_get_char(p_st_data, &u8_window);
    /* 根据协议window现在的值肯定为0 */
    if (i_ret != FR_SUCC || u8_window != 0x00)
    {
        goto unknown;
    }

    /* 判断是否是Sybase */
    i_sybase = frtds_detect_sybase(p_st_data, i_whole_flg, u8_type, &i_req_resp);
    bytebuff_free(&p_st_data);
    if (i_sybase != FRTDS_SYBASE_NO)
    {
        goto unknown;
    }

    /* 设置方向 */
    if( frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        if (u8_type == MSSQL_TDS_RESPONSE)
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
        else
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip , p_st_packet->dst_port);
        if (i_ret != FR_SUCC)
            frdbg("Set server ip and port failed!\n");
    }

    frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
    return APM_L7_IS_YES;

unknown:
    bytebuff_free(&p_st_data);
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            return APM_L7_IS_YES;
        }
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            return APM_L7_IS_YES;
        }
    }
    else
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }
    return APM_L7_IS_NO;
}

/*******************************************************************************
*  FUNC     :  SQL Server的packet解析
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_packet(入力packet信息)
            :  p_st_hash_report(保存Frreport_data)
*  RTN      :  参照module.h
*  NOTE     :
*******************************************************************************/
int sqlserver_analysis(Conntrack *p_st_conn
                      , Apm_packet *p_st_packet
                      , Frhash_header *p_st_hash_report)
{
    int i_ret = FR_SUCC;
    int i_whole_flg = FR_NO;                     /* 数据包完整标记 */
    int i_cancel_flg = MSSQL_NOT_CANCEL;               /* 请求取消标记 */
    uint8_t u8_packet_type = MSSQL_TDS_NUL;            /* packet类型 */
    L7_session *p_st_session = NULL;                   /* L7session */
    L7_fragment_sqlserver *p_st_fragment = NULL;       /* 分片包数据 */
    L7session_sqlserver_private *p_st_private = NULL;  /* MSSQL的私有数据 */

    if(p_st_conn == NULL || p_st_packet == NULL
        || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /*
    * 如果入力p_st_packet是FIN包, 说明本次MSSQL的connection结束,
    * 释放本次session信息. 如果入力p_st_packet是SYN包,说明新的MSSQL的
    * connection开始了, 释放上次可能残留的session信息
    */
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN
        || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        /* 销毁所有相关本次MSSQL的connection的数据 */
        sqlserver_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    /* 本次链路的第一个有效packet包,创建链路 */
    if (p_st_session->p_session_private == NULL)
    {
        /* 初始化SQL Server的私有数据 */
        i_ret = __sqlserver_init_private(p_st_session);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        /* 设置session ID */
        fruuid(p_st_session->arr_session_id);
    }

    p_st_private = (L7session_sqlserver_private *)p_st_session->p_session_private;
    /* 取得packet的TDS类型 */
    if (p_st_private->p_st_req)
    {
        u8_packet_type = p_st_private->p_st_req->u8_packet_type;
    }

    /* 设置解析数据 */
    i_ret = __sqlserver_set_analysis_data(p_st_private
                                         , p_st_packet->p_payload
                                         , p_st_packet->ui_payload_len
                                         , &(p_st_packet->st_timestamp)
                                         , &u8_packet_type
                                         , &i_cancel_flg
                                         , &i_whole_flg);
    if (i_ret != FR_SUCC)
    {
        frdbg("__sqlserver_set_analysis_data failed\n");
        __sqlserver_destroy_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }
    if (p_st_private->p_st_fragment->ui_total_len == 0)
    {
        return APM_L7_ANALYZE_TODO;
    }

    /* 根据packet type解析TDS数据包 */
    switch (u8_packet_type)
    {
        /* 普通SQL文 */
        case MSSQL_TDS_SQLBATCH:
            i_ret = sqlserver_parse_sqlbatch(p_st_conn, p_st_private
                                            , p_st_hash_report
                                            , i_cancel_flg, i_whole_flg);
            break;

        /* TDS7.0以下版本login，协议也未做定义,故忽略不做处理(之后扩展可考虑) */
        case MSSQL_TDS_PRETDS7LOGIN:
            i_ret = sqlserver_parse_pretds7login(p_st_conn, p_st_private
                                                , p_st_hash_report
                                                , i_cancel_flg, i_whole_flg);
            break;

        /* RPC request */
        case MSSQL_TDS_RPCREQUEST:
            i_ret = sqlserver_parse_rpc(p_st_conn, p_st_private
                                       , p_st_hash_report
                                       , i_cancel_flg, i_whole_flg);
            break;

        /* response */
        case MSSQL_TDS_RESPONSE:
            i_ret = sqlserver_parse_response(p_st_conn, p_st_private
                                            , p_st_hash_report, i_whole_flg);
            break;

        /* 说明：
        *  ATTENTION只有一个packet header，用来终止已经发送完整的request的操作
        *  故之前的request应该是没有响应，只有一个attection的响应DONE token
        */
        case MSSQL_TDS_ATTENTION:
            i_ret = sqlserver_parse_attention(p_st_conn, p_st_private
                                             , p_st_hash_report, i_whole_flg);
            if (i_ret == APM_L7_ANALYZE_TODO)
            {
                return APM_L7_ANALYZE_TODO;
            }
            break;

        /* 批量处理，此处语句应该是在服务端本地组包执行，网络抓包是抓不到不经过网卡的数据 */
        case MSSQL_TDS_BULKLOADBCP:
            i_ret = sqlserver_parse_bulk(p_st_conn, p_st_private
                                        , p_st_hash_report
                                        , i_cancel_flg, i_whole_flg);
            break;

        /* 事务管理 */
        case MSSQL_TDS_TRANSMGRREQ:
            i_ret = sqlserver_parse_transaction(p_st_conn, p_st_private
                                                , p_st_hash_report
                                                , i_cancel_flg, i_whole_flg);
            break;

        /* TDS版本7以上的login */
        case MSSQL_TDS_LOGIN7:
            /* 判断是不是一条链路发生了多个login, 概率较小 */
            if (p_st_private->i_in_session == FR_YES)
            {
                /* 为保留分片包数据,将p_st_private的成员p_st_fragment设为NULL */
                p_st_fragment = p_st_private->p_st_fragment;
                p_st_private->p_st_fragment = NULL;
                sqlserver_session_destroy((void *)p_st_private);
                p_st_session->p_session_private = NULL;
                i_ret = __sqlserver_init_private(p_st_session);
                if (i_ret != FR_SUCC)
                {
                    return APM_L7_ANALYZE_FAIL;
                }
                /* 重新设置分片包数据 */
                p_st_private = (L7session_sqlserver_private *)p_st_session->p_session_private;
                frfree(p_st_private->p_st_fragment);
                p_st_private->p_st_fragment = p_st_fragment;
            }

            /* LOGIN7解析 */
            i_ret = sqlserver_parse_login7(p_st_conn, p_st_private
                                          , p_st_hash_report
                                          , i_cancel_flg, i_whole_flg);
            /* login之后，设置链路处于session中 */
            p_st_private->i_in_session = FR_YES;
            break;

        /* SSPI,现今只取得内容，接下来如可解密还未实现 */
        case MSSQL_TDS_SSPIMESSAGE:
            i_ret = sqlserver_parse_sspi(p_st_conn, p_st_private
                                        , p_st_hash_report
                                        , i_cancel_flg, i_whole_flg);
            break;

        /* 预登陆 */
        case MSSQL_TDS_PRELOGIN:
            i_ret = sqlserver_parse_prelogin(p_st_conn, p_st_private
                                            , p_st_hash_report, i_whole_flg
                                            , MSSQL_CLI2SRV);
            break;

        default:    //实际环境中不会发生
            i_ret = APM_L7_ANALYZE_FAIL;
            break;
    }

    /* 解析出错 */
    if (i_ret == APM_L7_ANALYZE_FAIL)
    {
        frdbg("Prase [%d]packet failed!\n", u8_packet_type);
        __sqlserver_destroy_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 如果一个packet接收完整,解析后释放该packet信息 */
    if (i_whole_flg == FR_YES)
    {
        if (p_st_private->p_st_req)
        {
            p_st_private->p_st_req->u8_packet_type = 0;
        }
        sqlserver_init_fragment(p_st_private->p_st_fragment);
    }

    return i_ret;
}

/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session(Sql Server的私有session数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int sqlserver_session_destroy(void *p_private_session)
{
    L7session_sqlserver_private *p_st_private = (L7session_sqlserver_private *)p_private_session;

    /* 判断session是否为空 */
    if (p_st_private == NULL)
    {
        return FR_SUCC;
    }

    /* 设置该链路不在session中 */
    p_st_private->i_in_session = FR_NO;

    /* 销毁session数据 */
    if (p_st_private->p_st_sess)
    {
        sqlserver_destroy_session(&(p_st_private->p_st_sess));
    }

    /* 销毁request数据 */
    if (p_st_private->p_st_req)
    {
        sqlserver_destroy_request(&(p_st_private->p_st_req));
    }

    /* 销毁response数据 */
    if (p_st_private->p_st_resp)
    {
        sqlserver_destroy_response(&p_st_private->p_st_resp);
    }

    /* 销毁分片数据 */
    if (p_st_private->p_st_fragment)
    {
        sqlserver_destroy_fragment(&p_st_private->p_st_fragment);
    }

    /* 销毁prepare数据 */
    frhash2_free2(p_st_private->p_hash_prepare, frdb_statement_node_free);

    /* 销毁cursor数据 */
    frlist_remove_all(&(p_st_private->list_cursor), sqlserver_node_free);

    frfree(p_st_private);

    return FR_SUCC;
}
